home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 11
/
Cream of the Crop 11-2.iso
/
os2
/
gnucal.zip
/
gcal_tty.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-12-01
|
56KB
|
1,884 lines
/*
* gcal_tty.c: Manages the tty detection and I/O handling
*
*
* Copyright (C) 1994, 1995 Thomas Esken
*
* This software doesn't claim completeness, correctness or usability.
* On principle I will not be liable for any damages or losses (implicit
* or explicit), which result from using or handling my software.
* If you use this software, you agree without any exception to this
* agreement, which binds you LEGALLY !!
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the `GNU General Public License' as published by
* the `Free Software Foundation'; either version 2, or (at your option)
* any later version.
*
* You should have received a copy of the `GNU General Public License'
* along with this program; if not, write to the:
* Free Software Foundation
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*/
#ifdef RCSID
static char rcsid[]="$Id: gcal_tty.c 0.38 1995/12/01 00:03:08 tom Exp $";
#endif
/*
* Include header files
*/
#include "gcal_tai.h"
#if HAVE_CTYPE_H
# include <ctype.h>
#endif
#if HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#if USE_PAGER || USE_HLS
# if defined(UNIX) && !defined(DJG)
# if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
# include <termios.h>
# if HAVE_SYS_IOCTL_H && !defined(TIOCGWINSZ)
# include <sys/ioctl.h>
# endif
# else /* !HAVE_TERMIOS_H || !HAVE_TERMIOS_FUNCS */
# if HAVE_TERMIO_H
# include <termio.h>
# else /* !HAVE_TERMIO_H */
# include <sgtty.h>
# if HAVE_SYS_IOCTL_H && (defined(WIOCGETD) || defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP))
# include <sys/ioctl.h>
# endif
# endif /* !HAVE_TERMIO_H */
# endif /* !HAVE_TERMIOS_H || !HAVE_TERMIOS_FUNCS */
/*
* For the Unix PC (ATT 7300 & 3B1): (taken from less-278 by Mark Nudelman)
* Since WIOCGETD is defined in sys/window.h, we can't use that to decide
* whether to include sys/window.h. Use SIGPHONE from sys/signal.h instead.
*/
# ifndef TIOCGWINSZ
# include <sys/signal.h>
# ifdef SIGPHONE
# include <sys/window.h>
# endif
# endif
# if HAVE_SYS_STREAM_H
# include <sys/stream.h>
# endif
# if HAVE_SYS_PTEM_H
# include <sys/ptem.h>
# endif
# endif /* UNIX && !DJG */
# ifdef DJG
# include <pc.h>
# else /* !DJG */
# if defined(UNIX) || (defined(OS2) && defined(__GNUC__))
# if HAVE_TERMCAP_H && (HAVE_LIBTERMCAP || HAVE_LIBTERMLIB)
# if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS && defined(OS2) && defined(__GNUC__)
# include <termios.h>
# endif
# include <termcap.h>
# else /* !HAVE_TERMCAP_H || (!HAVE_LIBTERMCAP && !HAVE_LIBTERMLIB) */
# if HAVE_LIBTERMCAP || HAVE_LIBTERMLIB
IMPORT int tgetent __P_((char *buffer, char *termtype));
IMPORT int tgetnum __P_((char *name));
# if USE_HLS
IMPORT char *tgetstr __P_((char *name, char **area));
IMPORT char *tputs __P_((char *string, int nlines, int (*outfunc)()));
# endif
# if USE_PAGER
IMPORT int tgetflag __P_((char *name));
# endif /* USE_PAGER */
# endif /* HAVE_LIBTERMCAP || HAVE_LIBTERMLIB */
# endif /* !HAVE_TERMCAP_H || (!HAVE_LIBTERMCAP && !HAVE_LIBTERMLIB) */
# if MUST_DCL_OSPEED && USE_HLS
IMPORT short ospeed; /* Terminal output baud rate */
/*
On Solaris2, sys/types.h #includes sys/reg.h, which #defines PC.
Unfortunately, PC is a global variable used by the Termcap library.
*/
# ifdef PC
# undef PC
# endif
IMPORT char PC; /* Padding character */
# endif /* MUST_DCL_OSPEED && USE_HLS */
# endif /* UNIX || (OS2 && __GNUC__) */
# endif /* !DJG */
#endif /* USE_PAGER || USE_HLS */
#include "gcal.h"
/*
* Function prototypes
*/
#if __cplusplus
export "C"
{
#endif
/*
************************************************** Defined in `gcal_utl.c'
*/
IMPORT VOID_PTR
my_malloc __P_((const int amount,
const int exit_status,
const char *module_name,
const int module_line,
const char *var_name,
const int var_contents));
IMPORT void
my_error __P_((const int exit_status,
const char *module_name,
const int module_line,
const char *var_name,
const int var_contents));
IMPORT int
my_atoi __P_((const char *s));
/*
************************************************** Defined in `gcal_tty.c'
*/
EXPORT void
print_text __P_(( FILE *fp,
char *txt_line,
const Dmode_enum mode));
EXPORT void
get_tty_hls __P_((const char *sequence_str));
#if USE_PAGER
EXPORT void
get_tty_scr_size __P_((int *rows,
int *cols));
#endif
#if USE_HLS || USE_PAGER
# ifdef GCAL_TCAP
LOCAL Bool
open_termcap __P_((void));
# if USE_HLS
LOCAL void
get_ospeed __P_((void));
LOCAL int
outchar __P_((int ch));
LOCAL Bool
get_termcap_hls __P_((Bool *hls1_set,
Bool *hls2_set));
# endif /* USE_HLS */
# if USE_PAGER
LOCAL Bool
get_termcap_scr_attrib __P_((int *rows,
int *cols));
# endif /* USE_PAGER */
# else /* !GCAL_TCAP */
# if defined(MSDOS) && USE_PAGER
LOCAL Uchar
peek_byte __P_((Uint segment,
Uint offset));
# endif
# endif /* GCAL_TCAP */
#endif /* USE_HLS || USE_PAGER */
LOCAL void
get_hl_seq __P_((const char *sequence_str,
Bool *hls1_set,
Bool *hls2_set));
#if !HAVE_STRTOL
LOCAL int
sbyte2int __P_((const char *s,
const int base));
#endif
#if !HAVE_STRSTR
LOCAL char *
my_strstr __P_((const char *txt,
const char *pat));
#endif /* !HAVE_STRSTR */
#if __cplusplus
}
#endif
/*
* Declare public(extern) variables
*/
#ifdef GCAL_EMAIL
IMPORT FILE *tfp; /* Temporary file, which is send by mailer */
#endif
IMPORT Hls_struct ehls1s; /* Effective hls 1 start (current day) */
IMPORT Hls_struct ehls1e; /* Effective hls 1 end (current day) */
IMPORT Hls_struct ehls2s; /* Effective hls 2 start (holiday) */
IMPORT Hls_struct ehls2e; /* Effective hls 2 end (holiday) */
IMPORT int warning_level; /* --debug[=0...WARN_LVL_MAX] */
IMPORT int is_tty; /* Is output displayed on a terminal? */
IMPORT int is_tty1; /* Is output directed to channel 1? */
IMPORT int is_tty2; /* Is output directed to channel 2? */
IMPORT int tty_rows; /* Number of tty rows */
IMPORT int tty_cols; /* Number of tty columns */
IMPORT char s[MAXLEN+1]; /* General purpose text buffer */
#ifdef GCAL_EPAGER
IMPORT char *ext_pager; /* Name of external pager program */
#endif
IMPORT Bool emu_hls; /* Must we emulate the highlighting sequences? */
IMPORT Bool suppr_cal_flag; /* -u */
IMPORT Bool highlight_flag; /* -H<yes> or -H<no> */
#if USE_PAGER
IMPORT Bool pager_flag; /* -p */
#endif
/*
Define local(static) variables
*/
#if USE_PAGER || USE_HLS
# ifdef GCAL_TCAP
# if USE_HLS
LOCAL FILE *fp_outchar; /* File which tputs() uses */
# endif
LOCAL char tc_buf[4096]; /* Module global Termcap buffer */
LOCAL Bool tc_no_error=TRUE; /* Termcap access error occurred */
# if MUST_DCL_OSPEED && USE_HLS
extern short ospeed; /* Terminal output baud rate */
extern char PC; /* Padding character */
# endif
# endif /* GCAL_TCAP */
# if USE_PAGER
LOCAL Bool tty_am=TRUE; /* Terminal has automatic margins */
LOCAL Bool tty_xn=FALSE; /* Terminal ignores newline after wrap */
# endif /* USE_PAGER */
#endif /* USE_PAGER || USE_HLS */
#ifdef ANSI_PROTO
PUBLIC void
print_text ( FILE *fp,
char *txt_line,
const Dmode_enum mode)
#else /* !ANSI_PROTO */
PUBLIC void
print_text (fp, txt_line, mode)
FILE *fp;
char *txt_line;
const Dmode_enum mode;
#endif /* !ANSI_PROTO */
/*
This is the central tty output function, which works according to
actual display mode and suppress flag. It prints a line of text
given in `txt_line' with newline to file `fp' with paging option
(very poor and simple paging, only used if preprocessor symbol USE_PAGER
is defined) and deletes ALWAYS delivered `txt_line' automatically
after printing (*txt_line = '\0').
*/
{
if ( !suppr_cal_flag
|| ( suppr_cal_flag
&& (mode != CAlendar)))
{
#if USE_PAGER || (defined(GCAL_TCAP) && USE_HLS)
if ( is_tty
&& is_tty1
&& is_tty2
# ifdef GCAL_EPAGER
&& (ext_pager == (char *)NULL)
# endif
)
{
register int hls_pos=-1;
register int hls1_pos=-1;
register int hls2_pos=-1;
register int nl;
register int j;
# if USE_PAGER
register int k;
static int lines_printed=0;
# endif
auto int i=0;
auto int hls_chars=0;
auto char *ptr_1hls=(char *)NULL;
auto char *ptr_2hls=(char *)NULL;
auto Bool hls_start;
# if USE_PAGER
auto Bool print_hls=(Bool)(is_tty&&highlight_flag&&!emu_hls);
# endif
auto Bool nl_found=FALSE;
# if defined(GCAL_TCAP) && USE_HLS
fp_outchar = fp;
# endif
LOOP
{
j = 0;
nl = 0;
if ( highlight_flag
&& !emu_hls)
{
/*
Try to detect a highlighting sequence,
store its position and point to it...
*/
hls_pos=hls1_pos=hls2_pos = -1;
if (*(txt_line + i))
{
ptr_1hls = strstr(txt_line+i, ehls1s.seq);
if (ptr_1hls != (char *)NULL)
hls1_pos = (int)strlen(txt_line+i) - strlen(ptr_1hls);
ptr_2hls = strstr(txt_line+i, ehls2s.seq);
if (ptr_2hls != (char *)NULL)
hls2_pos = (int)strlen(txt_line+i) - strlen(ptr_2hls);
if ( (ptr_1hls != (char *)NULL)
&& (ptr_2hls != (char *)NULL))
{
if (hls1_pos > hls2_pos)
hls_pos = hls2_pos;
else
hls_pos = hls1_pos;
}
else
if (ptr_1hls != (char *)NULL)
hls_pos = hls1_pos;
else
if (ptr_2hls != (char *)NULL)
hls_pos = hls2_pos;
}
}
/*
No `\n'-NEWLINE character and no real highlighting sequence found:
print whole line
*/
if ( (strchr(txt_line, '\n') == (char *)NULL)
&& (ptr_1hls == (char *)NULL)
&& (ptr_2hls == (char *)NULL)
)
{
i = (int)strlen(txt_line);
fprintf(fp, "%s\n", txt_line);
}
else
{
hls_start = TRUE;
while (*(txt_line + i))
{
/*
`\n'-NEWLINE character found (actual line must be a RC
fixed date => TILDE-character expansion was performed):
print this newline
*/
if (*(txt_line + i) == '\n')
{
i++;
if (j)
nl++;
nl_found = TRUE;
break;
}
/*
Look for a real highlighting sequence;
if found, store its length in `hls_chars'
and print it explicitly
*/
if ( highlight_flag
&& !emu_hls
&& (i == hls_pos))
{
if (hls_pos == hls1_pos)
{
if (hls_start)
{
# if defined(GCAL_TCAP) && USE_HLS
tputs((char *)ehls1s.seq, 1, outchar);
# else /* !GCAL_TCAP || !USE_HLS */
fputs(ehls1s.seq, fp);
# endif /* !GCAL_TCAP || !USE_HLS */
hls_chars += ehls1s.len;
i += ehls1s.len;
ptr_1hls = strstr(txt_line+i, ehls1e.seq);
if (ptr_1hls != (char *)NULL)
hls_pos=hls1_pos = (int)(strlen(txt_line+i) - strlen(ptr_1hls)) + i;
else
hls_pos = hls2_pos;
hls_start = FALSE;
}
else
{
# if defined(GCAL_TCAP) && USE_HLS
tputs((char *)ehls1e.seq, 1, outchar);
# else /* !GCAL_TCAP || !USE_HLS */
fputs(ehls1e.seq, fp);
# endif /* !GCAL_TCAP || !USE_HLS */
hls_chars += ehls1e.len;
i += ehls1e.len;
ptr_1hls = strstr(txt_line+i, ehls1s.seq);
if (ptr_1hls != (char *)NULL)
hls_pos=hls1_pos = (int)(strlen(txt_line+i) - strlen(ptr_1hls)) + i;
else
hls_pos = hls2_pos;
hls_start = TRUE;
}
if (*(txt_line + i))
fputc(*(txt_line+i), fp);
else
break;
}
else
if (hls_pos == hls2_pos)
{
if (hls_start)
{
# if defined(GCAL_TCAP) && USE_HLS
tputs((char *)ehls2s.seq, 1, outchar);
# else /* !GCAL_TCAP || !USE_HLS */
fputs(ehls2s.seq, fp);
# endif /* !GCAL_TCAP || !USE_HLS */
hls_chars += ehls2s.len;
i += ehls2s.len;
ptr_2hls = strstr(txt_line+i, ehls2e.seq);
if (ptr_2hls != (char *)NULL)
hls_pos=hls2_pos = (int)(strlen(txt_line+i) - strlen(ptr_2hls)) + i;
else
hls_pos = hls1_pos;
hls_start = FALSE;
}
else
{
# if defined(GCAL_TCAP) && USE_HLS
tputs((char *)ehls2e.seq, 1, outchar);
# else /* !GCAL_TCAP || !USE_HLS */
fputs(ehls2e.seq, fp);
# endif /* !GCAL_TCAP || !USE_HLS */
hls_chars += ehls2e.len;
i += ehls2e.len;
ptr_2hls = strstr(txt_line+i, ehls2s.seq);
if (ptr_2hls != (char *)NULL)
hls_pos=hls2_pos = (int)(strlen(txt_line+i) - strlen(ptr_2hls)) + i;
else
hls_pos = hls1_pos;
hls_start = TRUE;
}
if (*(txt_line + i))
fputc(*(txt_line+i), fp);
else
break;
}
}
else
/*
Otherwise, print actual char in string
*/
fputc(*(txt_line+i), fp);
j++;
i++;
}
S_NEWLINE(fp);
}
# if USE_PAGER
if (pager_flag)
{
/*
Must we prompt the user?
*/
if (!tty_am)
j = 0;
else
{
k = ((nl_found) ? j : i) - nl - hls_chars;
j = k / tty_cols;
if ( j
&& tty_xn
&& !(k % tty_cols))
j--;
}
if (lines_printed+j >= tty_rows-1)
{
if (print_hls)
# if defined(GCAL_TCAP) && USE_HLS
tputs((char *)ehls1s.seq, 1, outchar);
# else /* !GCAL_TCAP || !USE_HLS */
fputs(ehls1s.seq, fp);
# endif /* !GCAL_TCAP || !USE_HLS */
# if USE_GER
fprintf(fp, "Weiter mit <Return> , <"PAGER_QUIT"> zum Beenden...");
# else /* !USE_GER */
fprintf(fp, "<Return> for more , <"PAGER_QUIT"> to quit...");
# endif /* !USE_GER */
if (print_hls)
# if defined(GCAL_TCAP) && USE_HLS
tputs((char *)ehls1e.seq, 1, outchar);
# else /* !GCAL_TCAP || !USE_HLS */
fputs(ehls1e.seq, fp);
# endif /* !GCAL_TCAP || !USE_HLS */
k = fgetc(stdin);
/*
Quit the pager by quit command
*/
if (tolower(k) == (int)*PAGER_QUIT)
{
/*
In case leading "quit" char and other text is in stdin buffer:
clean whole buffer
*/
while ( ((k=fgetc(stdin)) != '\n')
&& (k != EOF))
; /* Void */
k = EOF;
}
else
/*
In case "quit" char is not leading (anywhere) in stdin buffer:
clean buffer while "quit" char not found
*/
if (k != '\n')
while ( ((k=fgetc(stdin)) != '\n')
&& (tolower(k) != (int)*PAGER_QUIT)
&& (k != EOF))
; /* Void */
/*
In case "quit" char is found in stdin buffer now:
clean rest of buffer
*/
if (tolower(k) == (int)*PAGER_QUIT)
{
while ( ((k=fgetc(stdin)) != '\n')
&& (k != EOF))
; /* Void */
k = EOF;
}
/*
Exit program
*/
if (k == EOF)
exit(0);
/*
Begin scrolling of next page
*/
lines_printed = 0;
}
else
lines_printed += (j + 1);
if (!*(txt_line + i))
break;
}
else
# endif /* USE_PAGER */
if (!*(txt_line + i))
break;
}
}
else
#endif /* USE_PAGER || (GCAL_TCAP && USE_HLS) */
{
/*
If mailing option is selected, print output to temporary file
*/
if ( (tfp != (FILE *)NULL)
&& (fp != (FILE *)stderr))
fprintf(tfp, "%s\n", txt_line);
else
fprintf(fp, "%s\n", txt_line);
}
}
*txt_line = '\0';
}
#ifdef ANSI_PROTO
PUBLIC void
get_tty_hls (const char *sequence_str)
#else /* !ANSI_PROTO */
PUBLIC void
get_tty_hls (sequence_str)
const char *sequence_str;
#endif /* !ANSI_PROTO */
/*
Reads the colours/highlighting sequences from Termcap and assigns them
to the according variables. if Termcap isn't present, defaults are used.
*/
{
#if USE_HLS
auto char *ptr_env=getenv(ENV_VAR_GCALANSI);
# if defined(GCAL_TCAP)
auto const char *ptr_char;
# endif
#endif
auto Bool hls1_set=FALSE;
auto Bool hls2_set=FALSE;
/*
Check whether highlighting must be disabled (-H<no> given in command line)
*/
if (!highlight_flag)
{
emu_hls = TRUE;
ehls1s.seq = NO_HLS;
ehls1e.seq = NO_HLS;
ehls2s.seq = NO_HLS;
ehls2e.seq = NO_HLS;
}
else
{
/*
If output is not directed to a tty, emulate highlighting sequences
by marking characters
*/
if ( !is_tty
&& !emu_hls
&& highlight_flag)
emu_hls = TRUE;
/*
Check whether user defined highlighting sequences are given
in command line (-H<def>)
*/
if (sequence_str != (char *)NULL)
get_hl_seq (sequence_str, &hls1_set, &hls2_set);
/*
No or partitial highlighting sequences are given in command line
-> complete them
*/
if ( !hls1_set
|| !hls2_set)
{
#if USE_HLS
# ifdef GCAL_TCAP
if (!emu_hls)
{
/*
Try to open termcap file
*/
tc_no_error = open_termcap ();
if (tc_no_error)
get_termcap_hls (&hls1_set, &hls2_set);
if (ptr_env != (char *)NULL)
{
/*
Some or all Termcap highlighting sequences are missing:
--> use according default ANSI highlighting sequences
if environment variable GCALANSI is set
*/
if (!hls1_set)
{
ehls1s.seq = HLS1S;
ehls1e.seq = HLS1E;
}
if (!hls2_set)
{
ehls2s.seq = HLS2S;
ehls2e.seq = HLS2E;
}
}
else
if ( !hls1_set
|| !hls2_set)
{
/*
Some or all Termcap highlighting sequences are missing:
--> emulate ALL highlighting sequences by marking character
pairs if environment variable GCALANSI is not set
*/
emu_hls = TRUE;
ehls1s.seq = BUF_HLS1S;
ehls1e.seq = BUF_HLS1E;
ehls2s.seq = BUF_HLS2S;
ehls2e.seq = BUF_HLS2E;
}
}
else
# endif /* GCAL_TCAP */
{
if (emu_hls)
{
/*
Use emulation of highlighting sequences
in case output is not directed to a tty and the highlighting
sequences are not explicit disabled in command line by -H<no>
*/
if (!hls1_set)
{
ehls1s.seq = BUF_HLS1S;
ehls1e.seq = BUF_HLS1E;
}
if (!hls2_set)
{
ehls2s.seq = BUF_HLS2S;
ehls2e.seq = BUF_HLS2E;
}
}
else
{
/*
Use highlighting sequences directly in all other cases
*/
if (ptr_env != (char *)NULL)
{
/*
If environment variable GCALANSI is set:
--> use according default ANSI highlighting sequences
*/
if (!hls1_set)
{
ehls1s.seq = HLS1S;
ehls1e.seq = HLS1E;
}
if (!hls2_set)
{
ehls2s.seq = HLS2S;
ehls2e.seq = HLS2E;
}
}
else
if ( !hls1_set
|| !hls2_set)
{
/*
If environment variable GCALANSI is not set:
--> emulate ALL highlighting sequences by marking character pairs
*/
emu_hls = TRUE;
ehls1s.seq = BUF_HLS1S;
ehls1e.seq = BUF_HLS1E;
ehls2s.seq = BUF_HLS2S;
ehls2e.seq = BUF_HLS2E;
}
}
}
#else /* !USE_HLS */
/*
Use default highlighting sequences
*/
if (!hls1_set)
{
ehls1s.seq = HLS1S;
ehls1e.seq = HLS1E;
}
if (!hls2_set)
{
ehls2s.seq = HLS2S;
ehls2e.seq = HLS2E;
}
#endif /* !USE_HLS */
}
}
/*
Detect and store length of highlighting sequences
*/
#if defined(GCAL_TCAP) && USE_HLS
/*
Skip leading padding information for detection of real sequence length
*/
ptr_char = ehls1s.seq;
while (isdigit(*ptr_char))
ptr_char++;
ehls1s.len = (int)strlen(ptr_char);
ptr_char = ehls1e.seq;
while (isdigit(*ptr_char))
ptr_char++;
ehls1e.len = (int)strlen(ptr_char);
ptr_char = ehls2s.seq;
while (isdigit(*ptr_char))
ptr_char++;
ehls2s.len = (int)strlen(ptr_char);
ptr_char = ehls2e.seq;
while (isdigit(*ptr_char))
ptr_char++;
ehls2e.len = (int)strlen(ptr_char);
#else /* !GCAL_TCAP || !USE_HLS */
ehls1s.len = (int)strlen(ehls1s.seq);
ehls1e.len = (int)strlen(ehls1e.seq);
ehls2s.len = (int)strlen(ehls2s.seq);
ehls2e.len = (int)strlen(ehls2e.seq);
#endif /* !GCAL_TCAP || !USE_HLS */
}
#if USE_PAGER
# ifdef ANSI_PROTO
PUBLIC void
get_tty_scr_size (int *rows,
int *cols)
# else /* !ANSI_PROTO */
PUBLIC void
get_tty_scr_size (rows, cols)
int *rows;
int *cols;
# endif /* !ANSI_PROTO */
/*
Detects the number of rows and columns of a tty
and stores the values found in `rows' and `cols'
*/
{
# if !defined(AMIGA) || defined(__GNUC__)
register int li=0;
register int co=0;
auto char *ptr_env;
/*
First, look into the environment variable pair `LINES' and `COLUMNS'
resp., `LI' and `CO' in case these are defined and have valid settings:
use these settings
*/
ptr_env = getenv(ENV_VAR_LI);
if (ptr_env != (char *)NULL)
if (*ptr_env)
{
li = my_atoi (ptr_env);
ptr_env = getenv(ENV_VAR_CO);
if (ptr_env != (char *)NULL)
if (*ptr_env)
co = my_atoi (ptr_env);
}
if ( (li > 0)
&& (co > 0))
{
*rows = li;
*cols = co;
}
else
{
ptr_env = getenv(ENV_VAR_LI2);
if (ptr_env != (char *)NULL)
if (*ptr_env)
{
li = my_atoi (ptr_env);
ptr_env = getenv(ENV_VAR_CO2);
if (ptr_env != (char *)NULL)
if (*ptr_env)
co = my_atoi (ptr_env);
}
if ( (li > 0)
&& (co > 0))
{
*rows = li;
*cols = co;
}
else
{
# if defined(OS2) && defined(__GNUC__)
auto int info[2];
# endif /* OS2 && __GNUC__ */
# if defined(UNIX) && !defined(DJG)
# ifdef TIOCGWINSZ
auto struct winsize wsz;
# else /* !TIOCGWINSZ */
# ifdef WIOCGETD
auto struct uwdata wsz;
# endif
# endif /* !TIOCGWINSZ */
# endif /* UNIX && !DJG */
# if !defined(DJG) && !defined(MSDOS) && !defined(OS2) && !defined(UNIX)
/*
For these machines:
--> defaults only
*/
*rows = SCREEN_ROWS;
*cols = SCREEN_COLS;
# else /* DJG || MSDOS || OS2 || UNIX */
# ifdef DJG
/*
Get the actual number of lines and columns of the video
by calling the DJGPP-GCC ScreenRows() and ScreenCols() functions.
*/
*rows = ScreenRows();
*cols = ScreenCols();
# elif defined(MSDOS)
/*
Look directly into the pc-bios and get the actual number
of lines and columns of the video
*/
*rows = peek_byte (0x40, 0x84) + 1;
/*
Get lower part of 2-byte word
*/
*cols = peek_byte (0x40, 0x4b);
*cols <<= (Ulint)0x08;
/*
Add higher part of 2-byte word
*/
*cols += peek_byte (0x40, 0x4a);
# elif defined(OS2) && defined(__GNUC__)
/*
Get the actual number of lines and columns of the
video by calling the EMX-GCC _scrsize() function.
*/
_scrsize(info);
*cols = s[0];
*rows = s[1];
# elif defined(UNIX)
/*
Get the actual number of lines and columns of the
video by calling the ioctl() function.
*/
# ifdef TIOCGWINSZ
if ( !ioctl(1, TIOCGWINSZ, &wsz)
&& (wsz.ws_row > 0))
{
*rows = wsz.ws_row;
if ( !ioctl(1, TIOCGWINSZ, &wsz)
&& (wsz.ws_col > 0))
*cols = wsz.ws_col;
else
*rows = -1;
}
# else /* !TIOCGWINSZ */
# ifdef WIOCGETD
if ( !ioctl(1, WIOCGETD, &wsz)
&& (wsz.uw_height > 0))
{
*rows = wsz.uw_height / wsz.uw_vs;
if ( !ioctl(1, WIOCGETD, &wsz)
&& (wsz.uw_width > 0))
*cols = wsz.uw_width / wsz.uw_hs;
else
*rows = -1;
}
# endif
# endif /* !TIOCGWINSZ */
# endif /* UNIX */
if ( (*rows == -1)
&& (*cols == -1))
{
# if HAVE_LIBTERMCAP || HAVE_LIBTERMLIB
/*
If previous actions failed, try to open termcap file
*/
tc_no_error = open_termcap ();
if (tc_no_error)
{
if (!get_termcap_scr_attrib (rows, cols))
{
/*
No valid Termcap entries:
--> defaults only
*/
*rows = SCREEN_ROWS;
*cols = SCREEN_COLS;
}
}
else
{
/*
Access to termcap file has failed:
--> defaults only
*/
*rows = SCREEN_ROWS;
*cols = SCREEN_COLS;
}
# else /* !HAVE_LIBTERMCAP && !HAVE_LIBTERMLIB */
/*
No termcap file available:
--> defaults only
*/
*rows = SCREEN_ROWS;
*cols = SCREEN_COLS;
# endif /* !HAVE_LIBTERMCAP && !HAVE_LIBTERMLIB */
}
# endif /* DJG || MSDOS || OS2 || UNIX */
}
}
# else /* AMIGA && !__GNUC__ */
# ifdef AMIGA
/*
Amiga gets window size by asking the console.device
*/
{
auto long len;
auto char buf[30];
Write(Output(), "\2330 q", 4);
len = Read(Input(), buf, 29);
buf[len] = '\000';
sscanf(&buf[5], "%d;%d", rows, cols);
}
# else /* !AMIGA */
/*
All other systems:
--> defaults only
*/
*rows = SCREEN_ROWS;
*cols = SCREEN_COLS;
# endif /* !AMIGA */
# endif /* AMIGA && !__GNUC__ */
if (*rows > 1)
(*rows)--;
}
#endif /* USE_PAGER */
#if USE_PAGER || USE_HLS
# ifdef GCAL_TCAP
# ifdef ANSI_PROTO
LOCAL Bool
open_termcap (void)
# else /* !ANSI_PROTO */
LOCAL Bool
open_termcap ()
# endif /* !ANSI_PROTO */
/*
Tries to open the Termcap library and returns the terminal entry found
in the module global vector `tc_buf[4096]'. I cannot rely that we
use the access functions of the GNU Termcap library; which allow to pass
a NULL pointer to `tgetent()', so this function can check itself, how
large `tc_buf[]' must be and allocates it automatically; so i set
`tc_buf' to a size of 4096 bytes hoping, that this will be enough
for save program operation...
may be called only once.
returns FALSE if an error has occurred, otherwise TRUE.
*/
{
# if defined(OS2) && defined(__GNUC__)
auto char *ptr_env=getenv(ENV_VAR_TCAP);
auto char *ptr_tc;
# endif /* OS2 && __GNUC__ */
auto char *term=getenv(ENV_VAR_TERM);
static Bool tc_accessed=FALSE;
auto Bool is_error=FALSE;
if (!tc_accessed)
{
# if defined(OS2) && defined(__GNUC__)
/*
Under OS/2 with GNU-C, we use the default terminal type (ANSI)
and access Termcap library instead of printing an informational
message and using burned-in defaults if $TERM environment
variable isn't set.
*/
if ( term == (char *)NULL
|| !*term)
term = DFLT_TERM;
# else /* !OS2 || !__GNUC__ */
if (term == (char *)NULL)
{
# if USE_GER
if (warning_level >= 0)
fputs("\nUmgebungsvariable $"ENV_VAR_TERM" nicht vorhanden", stderr);
# else /* !USE_GER */
if (warning_level >= 0)
fputs("\nEnvironment variable $"ENV_VAR_TERM" not found", stderr);
# endif /* !USE_GER */
is_error = TRUE;
}
else
if (!*term)
{
# if USE_GER
if (warning_level >= 0)
fputs("\nUmgebungsvariable $"ENV_VAR_TERM" nicht gesetzt", stderr);
# else /* !USE_GER */
if (warning_level >= 0)
fputs("\nEnvironment variable $"ENV_VAR_TERM" not set", stderr);
# endif /* !USE_GER */
is_error = TRUE;
}
else
# endif /* !OS2 || !__GNUC__ */
{
# if defined(OS2) && defined(__GNUC__)
/*
Make sure the Termcap database is available,
i.e. store its access path in environment
explicitly so we are able to refer to it.
*/
if ( ptr_env == NULL
|| !*ptr_env)
{
ptr_env = (char *)my_malloc (256,
124, __FILE__, __LINE__ -1,
"ptr_env", 0);
_searchenv(FNAME_TCAP, "INIT", ptr_env);
if (!*ptr_env)
_searchenv(FNAME_TCAP, ENV_VAR_PATH, ptr_env);
if (!*ptr_env)
_searchenv(FNAME_TCAP, ENV_VAR_DPATH, ptr_env);
if (*ptr_env)
{
ptr_tc = (char *)my_malloc (strlen(ptr_env)+9,
124, __FILE__, __LINE__ -1,
"ptr_tc", 0);
sprintf(ptr_tc, ENV_VAR_TCAP"=%s", ptr_env);
putenv(ptr_tc);
}
free(ptr_env);
}
# endif /* OS2 && __GNUC__ */
switch (tgetent(tc_buf, term))
{
case -1:
# if USE_GER
if (warning_level >= 0)
fputs("\n`termcap' Datei wurde nicht vorgefunden", stderr);
# else /* !USE_GER */
if (warning_level >= 0)
fputs("\n`termcap' file not found", stderr);
# endif /* !USE_GER */
is_error = TRUE;
break;
case 0:
# if USE_GER
if (warning_level >= 0)
fputs("\nUnbekannter Terminaltyp in $"ENV_VAR_TERM" eingetragen", stderr);
# else /* !USE_GER */
if (warning_level >= 0)
fputs("\nUnknown terminal type defined in $"ENV_VAR_TERM, stderr);
# endif /* !USE_GER */
is_error = TRUE;
break;
default:
; /* Void, Termcap access ok */
}
}
if ( is_error
&& (warning_level >= 0))
fputs(".\n\n", stderr);
tc_accessed = TRUE;
return((Bool)!is_error);
}
else
return(tc_no_error);
}
# if USE_HLS
# ifdef ANSI_PROTO
LOCAL void
get_ospeed (void)
# else /* !ANSI_PROTO */
LOCAL void
get_ospeed ()
# endif /* !ANSI_PROTO */
/*
Try to detect terminal speed and store its value to
Termcap's global `ospeed' variable
*/
{
# if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
auto struct termios buf;
/*
Get terminal mode
*/
tcgetattr(1, &buf);
/*
Get ospeed
*/
# if HAVE_OSPEED
switch (cfgetospeed(&buf))
{
# ifdef B0
case B0:
ospeed = 0;
break;
# endif
# ifdef B50
case B50:
ospeed = 1;
break;
# endif
# ifdef B75
case B75:
ospeed = 2;
break;
# endif
# ifdef B110
case B110:
ospeed = 3;
break;
# endif
# ifdef B134
case B134:
ospeed = 4;
break;
# endif
# ifdef B150
case B150:
ospeed = 5;
break;
# endif
# ifdef B200
case B200:
ospeed = 6;
break;
# endif
# ifdef B300
case B300:
ospeed = 7;
break;
# endif
# ifdef B600
case B600:
ospeed = 8;
break;
# endif
# ifdef B1200
case B1200:
ospeed = 9;
break;
# endif
# ifdef B1800
case B1800:
ospeed = 10;
break;
# endif
# ifdef B2400
case B2400:
ospeed = 11;
break;
# endif
# ifdef B4800
case B4800:
ospeed = 12;
break;
# endif
# ifdef B9600
case B9600:
ospeed = 13;
break;
# endif
# ifdef EXTA
case EXTA:
ospeed = 14;
break;
# endif
# ifdef EXTB
case EXTB:
ospeed = 15;
break;
# endif
# ifdef B57600
case B57600:
ospeed = 16;
break;
# endif
# ifdef B115200
case B115200:
ospeed = 17;
break;
# endif
default:
; /* Void */
}
# endif /* HAVE_OSPEED */
# else /* !HAVE_TERMIOS_H || !HAVE_TERMIOS_FUNC */
# if TCGETA
auto struct termio buf;
/*
Get terminal mode
*/
ioctl(1, TCGETA, &buf);
/*
Get ospeed
*/
# if HAVE_OSPEED
ospeed = buf.c_cflag & CBAUD;
# endif
# else /* !TCGETA */
auto struct sgttyb buf;
/*
Get terminal mode
*/
ioctl(1, TIOCGETP, &buf);
/*
Get ospeed
*/
# if HAVE_OSPEED
ospeed = buf.sg_ospeed;
# endif
# endif /* !TCGETA */
# endif /* !HAVE_TERMIOS_H || !HAVE_TERMIOS_FUNC */
}
# ifdef ANSI_PROTO
LOCAL int
outchar (int ch)
# else /* !ANSI_PROTO */
LOCAL void
outchar (ch)
int ch;
# endif /* !ANSI_PROTO */
/*
Termcap's `tputs()' prints a character to module local defined
file `fp_outchar', which must be assigned before using `tputs()'.
*/
{
return(fputc(ch, fp_outchar));
}
# ifdef ANSI_PROTO
LOCAL Bool
get_termcap_hls (Bool *hls1_set,
Bool *hls2_set)
# else /* !ANSI_PROTO */
LOCAL Bool
get_termcap_hls (hls1_set, hls2_set)
Bool *hls1_set;
Bool *hls2_set;
# endif /* !ANSI_PROTO */
/*
Inspects the Termcap buffer `tc_buf' to detect the tty colour/highlighting sequences.
the module global vector `char tc_buf[]' must be filled previously.
may be called only once.
returns FALSE if an error has occured, otherwise TRUE.
*/
{
register int i=(*hls1_set) ? 2 : 0;
register int j=(*hls2_set) ? TC_MC_MAX-2 : TC_MC_MAX;
static char *tc[TC_MC_MAX]={
TC_MC_HL1S,
TC_MC_HL1E,
TC_MC_HL2S,
TC_MC_HL2E
};
# if HAVE_OSPEED
static char *padding;
# endif
static char *area;
auto char *ptr_char;
auto char *ptr_area;
auto Bool is_error=FALSE;
area = (char *)my_malloc (strlen(tc_buf),
124, __FILE__, __LINE__ -1,
"area", 0);
ptr_area = area;
# if HAVE_OSPEED
/*
Get the padding sequence
*/
padding = tgetstr("pc", &ptr_area);
PC = (padding) ? *padding : '\0';
/*
Get the terminal speed
*/
get_ospeed ();
# endif
for ( ; (i < j) && !is_error ; i++)
{
ptr_char = tgetstr(tc[i], &ptr_area);
if (ptr_char != (char *)NULL)
{
switch (i)
{
case 0:
ehls1s.seq = ptr_char;
break;
case 1:
ehls1e.seq = ptr_char;
*hls1_set = TRUE;
break;
case 2:
ehls2s.seq = ptr_char;
break;
case 3:
ehls2e.seq = ptr_char;
*hls2_set = TRUE;
break;
default:
/*
Error, more then 2 highlight sequence pairs given
*/
is_error = TRUE;
}
}
else
/*
Error, no terminal capability string found for mode `tc[i]'
*/
is_error = TRUE;
}
return((Bool)!is_error);
}
# endif /* USE_HLS */
# if USE_PAGER
# ifdef ANSI_PROTO
LOCAL Bool
get_termcap_scr_attrib (int *rows,
int *cols)
# else /* !ANSI_PROTO */
LOCAL Bool
get_termcap_scr_attrib (rows, cols)
int *rows;
int *cols;
# endif /* !ANSI_PROTO */
/*
Inspects the Termcap buffer `tc_buf' to detect first the amount of rows
and columns of the tty, then whether the terminal wraps the line
automatically at right margin. if Termcap isn't present, defaults are used.
the module global vector `char tc_buf[]' must be filled previously.
may be called only once.
returns FALSE if an error has occured, otherwise TRUE.
*/
{
/*
Get the amount of tty rows and columns
*/
if ( tgetnum("li") == -1
|| tgetnum("co") == -1)
return(FALSE);
else
{
*rows = tgetnum("li");
*cols = tgetnum("co");
/*
Check whether tty wraps the line automatically
at right margin and ignores newline after wrapping.
*/
tty_am = tgetflag("am");
tty_xn = tgetflag("xn");
}
return(TRUE);
}
# endif /* USE_PAGER */
# else /* !GCAL_TCAP */
# if defined(MSDOS) && USE_PAGER
# ifdef ANSI_PROTO
LOCAL Uchar
peek_byte (Uint segment,
Uint offset)
# else /* !ANSI_PROTO */
LOCAL Uchar
peek_byte (segment, offset)
Uint segment;
Uint offset;
# endif /* !ANSI_PROTO */
/*
Gets a byte of ibm/pc-memory from address (segment:offset)
*/
{
auto Ulint long_tmp;
auto Uchar far *ptr_char;
long_tmp = (Ulint)segment;
long_tmp <<= (Ulint)0x10;
long_tmp += (Ulint)offset;
ptr_char = (Uchar far *)long_tmp;
return(*ptr_char);
}
# endif /* MSDOS && USE_PAGER */
# endif /* !GCAL_TCAP */
#endif /* USE_PAGER || USE_HLS */
#ifdef ANSI_PROTO
LOCAL void
get_hl_seq (const char *sequence_str,
Bool *hls1_set,
Bool *hls2_set)
#else /* !ANSI_PROTO */
LOCAL void
get_hl_seq (sequence_str, hls1_set, hls2_set)
const char *sequence_str;
Bool *hls1_set;
Bool *hls2_set;
#endif /* !ANSI_PROTO */
/*
Highlighting sequences/marking characters are given in command line
(-H<seq1_start:seq1_end:seq2_start:seq2_end> option set)
i.e.: the colon separated string `sequence_str', which should contain
highlighting sequence/marking character pairs (2 pairs maximum,
first for actual day, second for holiday; seq?_start enables,
seq?_end disables), is delivered,
e.g.: \x20:\x20:\x1:#
marks holiday date like: \x1`date'#
using given marking characters.
e.g.: \x1b[34;42m:\x1b[0;40m or
\033[34;42m:\033[0;40m or
\E[34;42m:\E[0;40m
thus all defines starting (ANSI)escape highlighting sequence
\x1b[34;42m used for actual day and ending (ANSI)escape
highlighting sequence \x1b[0;40m with no given highlighting
sequence for holiday, so default highlighting sequences
for holiday are used (unnotated entries are always skipped).
control code definitions may contain any printable characters.
non-printable characters may be encoded in octal or hexadecimal
notation. The abbreviation \E resp., \e directly encodes the escape
character (\x1B resp., \033).
a character can be encoded octal by typing \nnn (BACKSLASH-octal
digit(s)), where n must be a valid octal digit (0...7). normally,
3 octal digits must be given. if the octal character code consists
of 1 or 2 octal digits, leading zeroes must be added; except the case,
the encoded octal character is given last in single sequence.
a character can be encoded hexadecimal by typing \xnn (BACKSLASH-x-
hexadecimal digit(s)), where n must be a valid hexadecimal digit
(0...9A...Fa...f). normally, 2 hexadecimal digits must be given. if
the hexadecimal character code consists of 1 hexadecimal digit,
a leading zero must be added; except the case, the encoded
hexadecimal character is given last in single sequence.
if the sequence separator character, the colon `:' character
itself is used for marking character, it must be specified
either octal by \072 or hexadecimal by \x3A.
get, convert and store them in the global hls structs.
returns TRUE if all actions are successfull, otherwise FALSE.
*/
{
register int i=0;
register int n;
register int j;
register int k;
register int diff;
register int seq_no=0;
static char *buf_hls[TC_MC_MAX];
auto const char *ptr_char=sequence_str;
auto char *ptr_err=(char *)NULL;
auto char hc_text[5];
auto Bool is_error=FALSE;
auto Bool is_hex;
auto Bool is_oct;
auto Bool is_esc;
*hls1_set=*hls2_set = FALSE;
while ( *ptr_char
&& !is_error
&& (seq_no < TC_MC_MAX))
{
/*
Copy highlighting sequence/marking character to temporary
sequence string (until column found)
*/
while( *ptr_char
&& (*ptr_char != *SEP)
&& (i < MAXLEN))
s[i++] = *ptr_char++;
/*
Skip if given sequence string is too long... :(
*/
if (i == MAXLEN)
break;
if (*ptr_char)
ptr_char++;
if (i)
{
s[i] = '\0';
i=n = 0;
/*
Convert all textual:
hex character sequences \xnn
oct character sequences \nnn
esc character sequences \E or \e
found in sequence string to real characters
*/
while (s[i+n])
{
is_hex=is_oct=is_esc = FALSE;
diff = 0;
if (s[i+n] == '\\')
{
is_esc = (Bool)(tolower(s[i+n+1]) == 'e');
is_hex = (Bool)(tolower(s[i+n+1]) == 'x');
is_oct = (Bool)isdigit(s[i+n+1]);
}
if (is_esc)
{
s[i] = '\033'; /* \x1b */
n++;
}
else
if ( is_hex
|| is_oct)
{
k = 0;
if (is_hex)
{
hc_text[k++] = '0';
hc_text[k++] = 'x';
}
else
{
if (s[i+n+1] != '0')
hc_text[k++] = '0';
else
diff = 1;
hc_text[k++] = s[i+n+1];
}
/*
Copy hex/oct digits to prefix
*/
j = i + n + 2;
while ( s[j]
&& (s[j] != *SEP)
&& (k < 4-diff))
hc_text[k++] = s[j++];
hc_text[k] = '\0';
/*
Convert textual hex/oct character to decimal value
*/
#if HAVE_STRTOL
j = (int)strtol(hc_text, &ptr_err, 0);
#else /* !HAVE_STRTOL */
ptr_err = hc_text + 1;
if (is_hex)
ptr_err++;
j = sbyte2int (ptr_err, (is_hex) ? 16 : 8);
#endif /* !HAVE_STRTOL */
/*
If conversion error occurs (either invalid chars in
hex/oct character sequence or \x0 resp., \000 given)
--> abort
*/
if ( !j
#if HAVE_STRTOL
|| *ptr_err
#endif
)
{
is_error = TRUE;
break;
}
/*
Put converted character code back to sequence string
*/
s[i] = (char)j;
n += (k - 2 + diff) + 1;
}
i++;
s[i] = s[i+n];
}
if (!is_error)
{
/*
Store highlighting sequence/marker character
in according global highlighting sequence
struct_variable using static buffer `buf_hls[]'
*/
n = (int)strlen(s);
buf_hls[seq_no] = (char *)my_malloc (n+1,
124, __FILE__, __LINE__ -1,
"buf_hls", seq_no);
strcpy(buf_hls[seq_no], s);
switch (seq_no)
{
case 0:
ehls1s.seq = buf_hls[seq_no];
ehls1s.len = n;
break;
case 1:
ehls1e.seq = buf_hls[seq_no];
ehls1e.len = n;
*hls1_set = TRUE;
break;
case 2:
ehls2s.seq = buf_hls[seq_no];
ehls2s.len = n;
break;
case 3:
ehls2e.seq = buf_hls[seq_no];
ehls2e.len = n;
*hls2_set = TRUE;
break;
default:
; /* Void */
}
}
}
i = 0;
seq_no++;
}
/*
Either real highlighting sequences (ESC-char..., lenght > 1) only or
marking characters (lenght == 1) only can be managed
-> avoid mixture of both...
*/
#if USE_HLS
if (*hls1_set)
if ( ( (ehls1s.len == 1)
&& (ehls1e.len != 1))
|| ( (ehls1s.len != 1)
&& (ehls1e.len == 1)))
*hls1_set = FALSE;
if (*hls2_set)
if ( ( (ehls2s.len == 1)
&& (ehls2e.len != 1))
|| ( (ehls2s.len != 1)
&& (ehls2e.len == 1)))
*hls2_set = FALSE;
if (*hls1_set)
{
if ( (ehls1s.len == 1)
&& (ehls1e.len == 1))
{
if (*hls2_set)
{
if ( (ehls2s.len == 1)
&& (ehls2e.len == 1))
emu_hls = TRUE;
else
{
if (emu_hls)
*hls2_set = FALSE;
else
*hls1_set = FALSE;
}
}
else
if (!emu_hls)
*hls1_set = FALSE;
}
else
{
if (*hls2_set)
{
if ( (ehls2s.len != 1)
&& (ehls2e.len != 1))
; /* Void, ok */
else
{
if (emu_hls)
*hls1_set = FALSE;
else
*hls2_set = FALSE;
}
}
else
if (emu_hls)
*hls1_set = FALSE;
}
}
if ( !*hls1_set
&& *hls2_set)
{
if ( (ehls2s.len == 1)
&& (ehls2e.len == 1))
{
if (!emu_hls)
*hls2_set = FALSE;
}
else
if (emu_hls)
*hls2_set = FALSE;
}
if ( *hls1_set
&& *hls2_set)
if ( emu_hls
&& (ehls1s.len > 1)
&& (ehls2s.len > 1))
*hls1_set=*hls2_set = FALSE;
#else /* !USE_HLS */
if (*hls1_set)
if ( ehls1s.len != 1
|| ehls1e.len != 1)
*hls1_set = FALSE;
if (*hls2_set)
if ( ehls2s.len != 1
|| ehls2e.len != 1)
*hls2_set = FALSE;
#endif /* !USE_HLS */
}
#if !HAVE_STRTOL
# ifdef ANSI_PROTO
LOCAL int
sbyte2int (const char *s,
const int base)
# else /* !ANSI_PROTO */
LOCAL int
sbyte2int (s, base)
const char *s;
const int base;
# endif /* !ANSI_PROTO */
/*
Converts a textual b-adic string `s', which contains the absolute
textual representation of a byte given in number base `base' (2-16)
to decimal base and returns its value converted to int in `res'.
If an error occurs, zero is returned.
*/
{
register int val;
register int res=0;
register int mul=1;
register int len=(int)strlen(s);
register int len_base_str;
static const char base_str[]="0123456789abcdef";
auto const char *ptr_char=s+(len-1);
len_base_str = (int)strlen(base_str);
if ( !len
|| base < 2
|| base > len_base_str)
return(0);
for ( ; len ; len--)
{
if (strchr(base_str, tolower(*ptr_char)) == (char *)NULL)
return(0);
val = len_base_str - (int)strlen(strchr(base_str, *ptr_char--));
if (val > base)
return(0);
res += (val * mul);
mul *= base;
}
return(res);
}
#endif /* !HAVE_STRTOL */
#if !HAVE_STRSTR
# ifdef ANSI_PROTO
LOCAL char *
my_strstr (const char *txt,
const char *pat)
# else /* !ANSI_PROTO */
LOCAL char *
my_strstr (txt, pat)
const char *txt;
const char *pat;
# endif /* !ANSI_PROTO */
/*
Search needle `pat' in haystack `txt' =8^)
(emulates the ANSI C strstr() function; not very well optimized).
*/
{
register int i=(int)strlen(txt);
register int j=(int)strlen(pat);
register int k;
auto const char *ptr_char=txt;
if (!j)
return(ptr_char);
if (i < j)
return((char *)NULL);
for (i=0 ; *ptr_char ; i++,ptr_char++)
{
for (k=0,j=i ; pat[k] && (txt[j]==pat[k]) ; j++,k++)
;
if ( k
&& !pat[k])
return(ptr_char);
}
return((char *)NULL);
}
#endif /* !HAVE_STRSTR */